/*
 * XMLGrammarReader.java
 *
 * Created on July 30, 2006, 6:44 PM
 *
 */

package galronnlp.io;

import galronnlp.cfg.grammar.NaryRule;
import galronnlp.cfg.lexicon.Word;
import galronnlp.perceptron.Chain;
import galronnlp.perceptron.Feature;
import galronnlp.perceptron.Grammar;
import galronnlp.util.ProductionGenerator;
import galronnlp.util.Symbol;
import galronnlp.util.SymbolGenerator;
import java.io.File;
import java.util.LinkedList;
import javax.xml.parsers.*;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * @author Daniel A. Galron
 */
public class XMLGrammarReader {

    XMLReader reader;
    public Grammar g;
    
    private ProductionGenerator pg;
    private SymbolGenerator sg;
    

    protected Chain chain;
    
    protected boolean expectChild = false;
    protected boolean expectChain = false;
    protected Symbol LHS;
    protected LinkedList<Symbol> RHS = new LinkedList<Symbol>();

    /** Creates a new instance of XMLGrammarReader */
    public XMLGrammarReader(String grammarFile, ProductionGenerator pg, SymbolGenerator sg) {
        this.pg = pg;
        this.sg = sg;
        this.g = new Grammar(pg, sg);
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser parser = factory.newSAXParser();
            reader = parser.getXMLReader();
            reader.setContentHandler(new grammarContentHandler());
            reader.parse(new File(grammarFile).toURL().toString());
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    public Grammar getGrammar() {
        return this.g;
    }
    
    public XMLGrammarReader(String grammarFile, ProductionGenerator pg, SymbolGenerator sg, Grammar g) {
        this.g = g;
        this.pg = pg;
        this.sg = sg;
        //this.g = new Grammar(pg, sg);
        SAXParserFactory factory = SAXParserFactory.newInstance();
        try {
            SAXParser parser = factory.newSAXParser();
            reader = parser.getXMLReader();
            reader.setContentHandler(new grammarContentHandler());
            reader.parse(new File(grammarFile).toURL().toString());
        } catch(Exception e) {
            e.printStackTrace();
        }
    }    
    
    public static void main(String args[]) {
        ProductionGenerator pg = new ProductionGenerator();
        SymbolGenerator sg = new SymbolGenerator();
        
        Grammar gram = new Grammar(pg, sg);
        
        XMLGrammarReader reader = new XMLGrammarReader(args[0], pg, sg);
        System.out.println(reader.g);
    }

    class grammarContentHandler extends DefaultHandler {
        public void startElement(String namespaceURI, String lname, String qname, Attributes attrs) throws SAXException {
            if(qname.equalsIgnoreCase("grammar")) {
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
                if(attrs.getLength() != 1) { System.err.println("ERROR! NO ATTRIBUTES DEFINED ON grammar ELEMENT"); throw new SAXException();}
                if(!attrs.getQName(0).equalsIgnoreCase("type")) { System.err.println("ERROR! INCORRECT ATTRIBUTE DEFINED ON grammar ELEMENT"); throw new SAXException();}
				if(attrs.getValue(0).equalsIgnoreCase("perceptron")) { g = new Grammar(pg, sg); }
				else {System.err.println("UNKNOWN GRAMMAR TYPE"); throw new SAXException();}
            }
            else if(qname.equalsIgnoreCase("parameters")) {
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
            }
            else if(qname.equalsIgnoreCase("feature")) {
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
                if(attrs.getLength() != 3) { System.err.println("ERROR! INCORRECT NUMBER OF ATTRIBUTES DEFINED ON feature ELEMENT"); }
                if(!attrs.getQName(0).equalsIgnoreCase("type") || !attrs.getQName(1).equalsIgnoreCase("label") || !attrs.getQName(2).equalsIgnoreCase("value")) { System.err.println("ERROR! UNKNOWN ATTRIBUTE IN feature ELEMENT!"); throw new SAXException(); }
                String type  = attrs.getValue(attrs.getQName(0));
                String label = attrs.getValue(attrs.getQName(1));
                String value = attrs.getValue(attrs.getQName(2));
                g.addParameter(new Feature(type, sg.create(label)), new Double(value).doubleValue());
            }
            else if(qname.equalsIgnoreCase("productions")) {
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
            }
            else if(qname.equalsIgnoreCase("rule")) {
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                expectChild = true;
                if(attrs.getLength() != 1) { System.err.println("ERROR! NO ATTRIBUTES DEFINED ON grammar ELEMENT"); throw new SAXException();}
                if(!attrs.getQName(0).equalsIgnoreCase("lhs")) { System.err.println("ERROR! UNKNOWN ATTRIBUTE IN grammar ELEMENT!"); throw new SAXException(); }
                LHS = sg.create(attrs.getValue(attrs.getQName(0)));
            }
            else if(qname.equalsIgnoreCase("child")) {
                if(!expectChild) { System.err.println("ERROR! CHILD ELEMENT NOT EXPECTED"); throw new SAXException(); }
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                if(attrs.getLength() != 1) { System.err.println("ERROR! NO ATTRIBUTES DEFINED ON child ELEMENT"); throw new SAXException();}
                if(!attrs.getQName(0).equalsIgnoreCase("node")) { System.err.println("ERROR! UNKNOWN ATTRIBUTE IN child ELEMENT!"); throw new SAXException(); }
                RHS.addLast(sg.create(attrs.getValue(attrs.getQName(0))));
            }
            else if(qname.equalsIgnoreCase("lex")) {
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                if(attrs.getLength() != 2) { System.err.println("ERROR! NO ATTRIBUTES DEFINED ON lex ELEMENT"); throw new SAXException();}
                if(!attrs.getQName(0).equalsIgnoreCase("cat") || !attrs.getQName(1).equalsIgnoreCase("entry")) { System.err.println("ERROR! UNKNOWN ATTRIBUTE IN lex ELEMENT!"); throw new SAXException(); }
                Word w = new Word(sg.create(attrs.getValue(attrs.getQName(0))), sg.create(attrs.getValue(attrs.getQName(1))));
                g.addRule(w);
            }
            else if(qname.equalsIgnoreCase("chain")) {
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
                expectChain = true;
                if(attrs.getLength() != 0) { System.err.println("ERROR! INCORRECT NUMBER OF ATTRIBUTES DEFINED ON chain ELEMENT"); throw new SAXException();}
                chain = new Chain();
            }
            else if(qname.equalsIgnoreCase("node")) {
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
                if(!expectChain) { System.err.println("ERROR! NODE NOT ELEMENT EXPECTED"); throw new SAXException(); }
                if(attrs.getLength() != 1) { System.err.println("ERROR! NO ATTRIBUTES DEFINED ON node ELEMENT"); throw new SAXException();}
                if(!attrs.getQName(0).equalsIgnoreCase("label")) { System.err.println("ERROR! UNKNOWN ATTRIBUTE IN feature ELEMENT!"); throw new SAXException(); }
                chain.append(sg.create(attrs.getValue(attrs.getQName(0))));
            }
            else if(qname.equalsIgnoreCase("allowable")) {
                if(expectChild) { System.err.println("ERROR! CHILD ELEMENT EXPECTED"); throw new SAXException(); }
                if(expectChain) { System.err.println("ERROR! NODE ELEMENT EXPECTED"); throw new SAXException(); }
                if(attrs.getLength() != 3) { System.err.println("ERROR! NO ATTRIBUTES DEFINED ON allowable ELEMENT"); throw new SAXException();}
                if(!attrs.getQName(0).equalsIgnoreCase("parent") || !attrs.getQName(1).equalsIgnoreCase("sibling") || !attrs.getQName(2).equalsIgnoreCase("node")) { System.err.println("ERROR! UNKNOWN ATTRIBUTE IN allowable ELEMENT!"); throw new SAXException(); }
                g.addAllowableTriple(sg.create(attrs.getValue(attrs.getQName(0))), sg.create(attrs.getValue(attrs.getQName(1))), sg.create(attrs.getValue(attrs.getQName(2))));
            }
            else throw new SAXException();
        }
        public void endElement (String uri, String localName, String qName) throws SAXException {
            if(qName.equalsIgnoreCase("rule")) {
                expectChild = false;
                NaryRule r = new NaryRule(LHS, RHS);
                LHS = null;
                RHS = new LinkedList<Symbol>();
                g.addRule(r);
            }
            if(qName.equalsIgnoreCase("chain")) {
                expectChain = false;
                g.addChain(chain);
                chain = null;
            }            
        }
    }
    
}
